#ifndef MOCHA_DETAIL_REGION_HPP_INCLUDED
#define MOCHA_DETAIL_REGION_HPP_INCLUDED

/**
 * @file
 */

#include <cmath>
#include <iostream>
#include <cml/cml.h>
#include "mocha/math.hpp"

namespace mocha {
/**
 * Rectangular region.
 * @param T 
 */
template<typename T>
struct region {
	region(): x(0), y(0), w(0), h(0) {}
	region(const T& x, const T& y, const T& w, const T& h): x(x), y(y), w(w), h(h) {}
	template<typename U>
	region(const region<U>& other): x(static_cast<T>(other.x)), y(static_cast<T>(other.y)), w(static_cast<T>(other.w)), h(static_cast<T>(other.h)) {}
	T x, y, w, h;
};
/**
 * Sets all components of a region to zero.
 * @param T 
 * @param r Region.
 */
template<typename T>
void zero(region<T>& r) {
	r.x = r.y = r.w = r.h = 0;
}
/**
 * @param T 
 * @param r Region.
 * @return True if the region is square, otherwise false.
 */
template<typename T>
bool square(const region<T>& r) {
	return r.w == r.h;
}
/**
 * @param T 
 * @param r Region.
 * @return Area of the region.
 */
template<typename T>
const T area(const region<T>& r) {
	return r.w * r.h;
}
/**
 * @param T 
 * @param r Region.
 * @return The top of the region.
 */
template<typename T>
const T& top(const region<T>& r) {
	return r.y;
}
/**
 * Sets the top of a region.
 * @param T 
 * @param r Region.
 * @param t Top.
 * @return The (new) top of the region.
 */
template<typename T>
T& top(region<T>& r, const T& t) {
	return r.y = t;
}
/**
 * @param T 
 * @param r Region.
 * @return The left of the region.
 */
template<typename T>
const T& left(const region<T>& r) {
	return r.x;
}
/**
 * Sets the left side of the region.
 * @param T 
 * @param r Region.
 * @return The (new) left of the region.
 */
template<typename T>
T& left(region<T>& r, const T& l) {
	return r.x = l;
}
/**
 * @param T 
 * @param r Region.
 * @return The bottom of the region.
 */
template<typename T>
const T bottom(const region<T>& r) {
	return r.y + r.h;
}
template<typename T>
T bottom(region<T>& r, const T& b) {
	r.h = b - r.y;
	return b;
}
template<typename T>
const T right(const region<T>& r) {
	return r.x + r.w;
}
template<typename T>
T right(region<T>& r, const T& rr) {
	r.w = rr - r.x;
	return rr;
}
template<typename T>
region<T> join(const region<T>& r1, const region<T>& r2) {
	return region<T>(std::min(r1.x, r2.x), std::min(r1.y, r2.y), std::max(r1.w, r2.w), std::max(r1.h, r2.h));
}
template<typename T, typename U>
bool collision(const region<T>& r, const cml::vector<U, cml::fixed<2> >& p) {
	return (r.x < p[0]) && (right(r) > p[0]) && (r.y < p[1]) && (bottom(r) > p[1]);
}
template<typename T, typename U>
region<T> collision(const region<T>& r, const region<U>& q) {
	return region<T>(); // TODO: 
}
template<typename T>
std::ostream& operator<<(std::ostream& lhs, const region<T>& rhs) {
	lhs << rhs.w << "x" << rhs.h << " at (" << rhs.x << ", " << rhs.y << ")";
	return lhs;
}
}

#endif

